/**
 * DVN: Distributed Virtual Network Simulation Platform
 * Copyright (c) 2006-2009 Tyson Malchow <tyson.malchow@gmail.com>
 *
 * This file is part of the DVN distributed virtual network simulation
 * program.
 *
 * DVN is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DVN is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with DVN.  If not, see <http://www.gnu.org/licenses/>.
 */
#ifndef _vci_h
#define _vci_h

/**
 		Virtual Communications Interfacing
*/


#include <sys/time.h>
#include <time.h>
#include <netinet/in.h>

#include "vci.h"
#include "hashtable.h"
#include "btree.h"
#include "evtracker.h"
#include "nbdf.h"
#include "context.h"
#include "events.h"

#define VCI_MAX_DATAGRAM_SIZE 8192 /**< maximum size of a VCI UDP simulated datagram - messages larger than this are dropped */

#define VCI_RLBLTY_100 1000000000 /**< 100% reliability - using fixed point math */
#define VCI_RLBLTY_FAC 10000000   /**< scaling factor used for the fixed point math */

/**
 * defines how tight we want the distribution around the average value:
 * 0 = normal distribution, 1 = loose, 10 = very tight
 */
#define VCI_NETMODEL_TIGHTNESS_FACTOR 5

/**
 * Any VCI network message uses this message format
 */
typedef struct vci_msg_t {
		in_addr_t to_addr;
		int to_port;

		in_addr_t from_addr;
		int from_port;

		unsigned int network_source_id;
		ptime_t deliver_time;

		unsigned int data_size;
		char * data;
} vci_msg_t, *vci_msg_tp ;

typedef struct vci_addressing_scheme_t {
	unsigned int slave_mask;

	unsigned int worker_shiftcount;
	uint32_t worker_mask;

	uint32_t node_shiftcount;
	unsigned int node_randmax;
} vci_addressing_scheme_t, *vci_addressing_scheme_tp;

typedef struct vci_netmodel_t {
	unsigned int base_delay;
	unsigned int width;
	unsigned int tail_width;
	unsigned int reliability;
} vci_netmodel_t, *vci_netmodel_tp;

/* defines the numbers necessary to connect network endpoints */
typedef struct vci_network_connection_t {
	unsigned char active; /*if this connection is active */
	vci_netmodel_t netmodel;
} vci_network_connection_t, *vci_network_connection_tp;

/* a single subnet of a larger network */
typedef struct vci_network_t {
	/* implicit internal message delivery connection */
	vci_netmodel_t netmodel;

	/* all remote network connections */
	hashtable_tp remote_connections;

	/* 1 if this network is live */
	unsigned char active;

	/* network id */
	unsigned int netid;
} vci_network_t,*vci_network_tp;

typedef struct vci_socket_t {
	vci_onrecv_cb_tp callback;
} vci_socket_t, *vci_socket_tp;

typedef struct vci_mailbox_t {
	context_provider_tp context_provider;
	btree_tp sockets;
	vci_network_tp network_membership;
} vci_mailbox_t, *vci_mailbox_tp;

/**
 * a VCI manager
 *
 * this it holds some quantity of vci-addressable endpoints, along with the mechanisms for ordered
 * delivery
 */
typedef struct vci_mgr_t {
	/** total number of slaves in this simulation */
	//unsigned int num_slaves;

	/** total number of workers on this slave */
	//unsigned int num_workers;

	events_tp events;

	vci_addressing_scheme_tp ascheme;

	/** */
	unsigned int slave_id;
	unsigned int worker_id;

	/** current address counter */
	unsigned int c_adr_cnt;

	/** all possible endpoints this block manages */
	hashtable_tp mailboxes;

	/** all virtual networks available */
	hashtable_tp networks;

	/** the last time we sent a message to a different worker */
	ptime_t last_remote_sent_at;

	struct timeval minstamp;
} vci_mgr_t, * vci_mgr_tp;


vci_addressing_scheme_tp vci_create_addressing_scheme (int num_slaves, int max_wrkr_per_slave);
unsigned int vci_ascheme_rand_node (vci_addressing_scheme_tp scheme);
void vci_destroy_addressing_scheme (vci_addressing_scheme_tp scheme);
unsigned int vci_ascheme_get_worker (vci_addressing_scheme_tp scheme, in_addr_t ip);
unsigned int vci_ascheme_get_slave (vci_addressing_scheme_tp scheme, in_addr_t ip);
unsigned int vci_ascheme_get_node (vci_addressing_scheme_tp scheme, in_addr_t ip);
in_addr_t vci_ascheme_build_addr(vci_addressing_scheme_tp scheme, unsigned int slave_id, unsigned int worker_id, unsigned int node_id);
vci_mgr_tp vci_mgr_create (events_tp events, unsigned int slave_id, unsigned int worker_id, vci_addressing_scheme_tp scheme);
ptime_t vci_get_last_processed(vci_mgr_tp mgr);

void vci_free_ip(vci_mgr_tp mgr, in_addr_t addr);
void vci_mgr_destroy(vci_mgr_tp mgr);
in_addr_t vci_create_ip(vci_mgr_tp mgr, int net_id, context_provider_tp cp);
vci_mailbox_tp vci_get_mailbox(vci_mgr_tp mgr, in_addr_t ip);
int vci_create_datagram_socket(vci_mgr_tp mgr, in_addr_t ip, unsigned int port, vci_onrecv_cb_tp callback);
void vci_close_socket(vci_mgr_tp mgr, in_addr_t ip, int socketid);

/**
 * Provides the underlying model for the network layer
 *
 * Based on the delay measurements in turbo-King
 * http://inl.info.ucl.ac.be/blogs/08-04-23-turbo-king-framework-large-scale-internet-delay-measurements
 * Paper:  http://irl.cs.tamu.edu/people/derek/papers/infocom2008.pdf
 * Note that we are looking mostly at link delay since we are modeling an inter AS delay
 *
 * We expect a CDF as follows:

   1|                         +++++++++++++++
    |                     +++
    |                  ++
    |                 +
    |                +
    |                +
    |                +
    |                +
    |                +
    |                +
    |               +
    |               +
    |              +
   0+++++++++++++++-----------------------------
    0                |
                Base Delay
                 |<----->|<----------|
                  Width      Tail
 */
unsigned int vci_model_delay(vci_netmodel_tp netmodel);
int vci_send (
		vci_mgr_tp mgr,
		ptime_t curtime,
		in_addr_t source_addr,
		int from_socket_id,
		in_addr_t to_addr,
		int to_port,
		const char * data,
		const unsigned int size );
int vci_deposit (vci_mgr_tp mgr, nbdf_tp frame);
vci_network_tp vci_network_create(vci_mgr_tp mgr, unsigned int id, unsigned int base_delay, unsigned int width, unsigned int tail_width, unsigned int reliability);
void vci_network_connect( vci_mgr_tp mgr, int netid1, int netid2,
									unsigned int base_delay,
									unsigned int width,
									unsigned int tail_width,
									unsigned int reliability) ;
void vci_network_disconnect( vci_mgr_tp mgr, int netid1, int netid2 );
void vci_exec_event (vci_mgr_tp mgr, void * event);
void vci_free_event (void * event);



#ifndef INADDR_LOOPBACK
#define INADDR_LOOPBACK 0x0100007f
#endif

#ifndef INADDR_NONE
#define INADDR_NONE ((unsigned long) -1)
#endif


#endif
